/*
example.cpp: example file for the Fudepan XML Parser project.
    Copyright (C) 2009, 2010  Daniel Gutson, FuDePAN

    This file is part of the FXP project.

    FXP is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    FXP is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with FXP.  If not, see <http://www.gnu.org/licenses/>.

    Build this example as:
        make
*/

#include <vector>
#include <set>
#include <list>
#include <string>
#include <iostream>

#include "fx-parser/fxp.h"

using namespace std;
using namespace fxp;

#define LOVMethod

struct Grupo
{
    struct Supertype
    {
    private:
        const string name;
        const int x;
        const int y;
        float z;

    public:
#ifdef LOVMethod
        struct PositionData
        {
            size_t pos;
            string type;
        };
        std::list<PositionData> positions;
#else
        set<size_t> positions;
#endif
        Supertype(const string& name, int x, int y)
            : name(name), x(x), y(y), z(0.0f)
        {}
        void set_z(float value)
        {
            z = value;
        }
        const string& get_name() const
        {
            return name;
        }
        int get_x() const
        {
            return x;
        }
        int get_y() const
        {
            return y;
        }
        float get_z() const
        {
            return z;
        }
#ifdef LOVMethod
        void add_position(size_t pos, const string& type)
        {
            PositionData pd = { pos, type };
            positions.push_back(pd);
        }
#endif

        bool operator<(const Supertype& other) const
        {
            return name < other.name;
        }
    };

    string name;
    set<Supertype> supertypes;
};

typedef list<Grupo> ExecutionData;

static void show_data(const ExecutionData& xd);

int main()
{
    bool ret;
    ParseErrorData ped;
    ExecutionData xd;   /* results here */

#ifdef LOVMethod
    FXParserLOVMethod<Grupo::Supertype, void, Parameters2<size_t, const string&> > xmlPositions("position", &Grupo::Supertype::add_position);
    xmlPositions.parameters.set_param0("pos");
    xmlPositions.parameters.set_param1("type", "NotSet");
#endif

    FXParserNonDef<Grupo::Supertype, Constructor3<Grupo::Supertype, string, int, int> > xmlSupertype("supertype");
    xmlSupertype.constructor.set_param0("id");
    xmlSupertype.constructor.set_param1("x", -1);
    xmlSupertype.constructor.set_param2_constant(-2);
    add_attr(xmlSupertype, "z", &Grupo::Supertype::set_z);
#ifdef LOVMethod
    add_lov_child(xmlSupertype, xmlPositions);
#else
    add_lov_child(xmlSupertype, string("position"), string("pos"), &Grupo::Supertype::positions);
#endif

    FXParser<Grupo> xmlGrupo("grupo");
    add_child(xmlGrupo, &Grupo::supertypes, xmlSupertype);
    add_attr(xmlGrupo, "id", &Grupo::name);

    FXPRootParser<ExecutionData> dataParser("data", xmlGrupo);
    ignore_attr(dataParser, "ignore_me");

    /* sino, si fuera una estructura comun, seria:
    FXPRootParser<ExecutionData> dataParser("data");
        add_child(dataParser, xmlGrupo, &ExecutionData::grupos);
        ignore_attr(dataParser, "ignore_me");
    */

    ret = parse_xml("projects/fx-parser/example/test.xml", xd, dataParser, ped, Warn, Warn);

    if (ret)
    {
        show_data(xd);
    }
    else
    {
        cerr << "Error: " << ped.error << " at line " << ped.line << endl;
    }

    return 0;
}

static void show_data(const ExecutionData& xd)
{
    cout << "Groups:" << endl;

    for (ExecutionData::const_iterator grupo = xd.begin(); grupo != xd.end(); ++grupo)
    {
        cout << "\tName: " << grupo->name << endl;
        cout << "\tSupertypes:" << endl;

        for (set<Grupo::Supertype>::const_iterator st = grupo->supertypes.begin(); st != grupo->supertypes.end(); ++st)
        {
            cout << "\t\tName: " << st->get_name() << endl;
            cout << "\t\tX: " << st->get_x() << endl;
            cout << "\t\tY: " << st->get_y() << endl;
            cout << "\t\tZ: " << st->get_z() << endl;
            cout << "\t\tPositions: ";

#ifdef LOVMethod
            for (std::list<Grupo::Supertype::PositionData>::const_iterator pos = st->positions.begin(); pos != st->positions.end(); ++pos)
                cout << "[" << pos->pos << " " << pos->type << "] ";
#else
            for (set<size_t>::const_iterator pos = st->positions.begin(); pos != st->positions.end(); ++pos)
                cout << *pos << " ";
#endif
            cout << endl;
        }
    }
}

